/*
 * jQuery Scrollbars
 * 
 * Copyright (c) 2010 Sam Holmes
 * Dual licensed under the MIT and Creative Commons 3.0 BY-SA licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://creativecommons.org/licenses/by-sa/3.0/
 */

(function($) {
	function createElementWithClass(name, className) {
		var ele = document.createElement(name);
		ele.className = className;
		return ele;
	}
	$.fn.scrollbars = function() {
		var options = {
			overflowX: "auto",
			overflowY: "auto",
			stealth: false
		};
		
		this.each(function(){
			if (this.alignInterval == undefined) {
				var content = this,
					$content = $(content);
				var scrollbar = createElementWithClass('div', 'scrollbar-vertical');
				scrollbar.track = createElementWithClass('div', 'track');
				scrollbar.upArrow = createElementWithClass('div', 'arrow-up');
				scrollbar.downArrow = createElementWithClass('div', 'arrow-down');
				scrollbar.tab = createElementWithClass('div', 'tab');
				scrollbar.tabTop = createElementWithClass('div', 'top');
				scrollbar.tabBottom = createElementWithClass('div', 'bottom');
				var startedDragPos, startedOffsetPos, 
					contentWidth, contentHeight,
					trackMargins, trackHeight, 
					tabMargins, tabHeight;
				
				function alignScrollBars() {
					contentWidth = $content.width()+
						(+$content.css("borderLeftWidth").replace(/\D*/g, ""))+
						(+$content.css("borderRightWidth").replace(/\D*/g, ""))+
						(+$content.css("paddingLeft").replace(/\D*/g, ""))+
						(+$content.css("paddingRight").replace(/\D*/g, ""));
					contentHeight = $content.height()+
						(+$content.css("borderTopWidth").replace(/\D*/g, ""))+
						(+$content.css("borderBottomWidth").replace(/\D*/g, ""))+
						(+$content.css("paddingTop").replace(/\D*/g, ""))+
						(+$content.css("paddingBottom").replace(/\D*/g, ""));  
					trackMargins = (+$(scrollbar.track).css('marginTop').replace(/\D*/g, "")) + (+$(scrollbar.track).css('marginBottom').replace(/\D*/g, ""));
					trackHeight = contentHeight - trackMargins;
					tabMargins = parseInt($(scrollbar.tab).css('marginTop')) + parseInt($(scrollbar.tab).css('marginBottom'));
					tabHeight = trackHeight * (content.clientHeight / content.scrollHeight) | 0; // The | 0 part is to turn it into an integer
					
					//If the scrolling exceeds it's limits
					if (content.scrollTop > content.scrollHeight - content.clientHeight)
						content.scrollTop = content.scrollHeight; //Then set it to it's limits
					
					//Hide vertical scrollbar if it's too small
					if (trackHeight < tabHeight + tabMargins)
						$(scrollbar).css("display", "none");
					else
						$(scrollbar).css("display", "");
					
					$(scrollbar.track).height(trackHeight).css({
						top: $content.offset().top,
						left: $content.offset().left + contentWidth
					});
					$(scrollbar.tab).height(tabHeight);
					
					var limit = trackHeight - (tabHeight + tabMargins);
					$(scrollbar.tab).css('top', limit * (content.scrollTop/(content.scrollHeight-content.clientHeight)));
				}
				
				$(scrollbar).append(scrollbar.track);
				$(scrollbar.track)
					.append(scrollbar.tab)
					.append(scrollbar.upArrow)
					.append(scrollbar.downArrow);
				$(scrollbar.tab)
					.append(scrollbar.tabTop)
					.append(scrollbar.tabBottom)
					.mouseenter(function() {
						$(this).addClass('tab-hover');
					})
					.mouseleave(function() {
						$(this).removeClass('tab-hover');
					})
					.mousedown(function(event){
						$(this).addClass('tab-active');
						startedDragPos = event.clientY;
						startedOffsetPos = parseInt($(this).css('top').substr(0, $(this).css('top').length - 2));
						return false;
					});
				$(scrollbar.upArrow)
					.mouseenter(function() {
						$(this).addClass('arrow-up-hover');
					})
					.mouseleave(function() {
						$(this).removeClass('arrow-up-hover');
					})
					.mousedown(function() {
						$(this).addClass('arrow-up-active');
						
						clearInterval(this.scrollInterval);
						this.scrollInterval = setInterval(function() {
							content.scrollTop -= content.clientHeight * .01;
						}, 1);
						return false;
					})
					.mouseup(function() {
						$(this).removeClass('arrow-up-active');
						clearInterval(this.scrollInterval);
					});
				$(scrollbar.downArrow)
					.mouseenter(function() {
						$(this).addClass('arrow-down-hover');
					})
					.mouseleave(function() {
						$(this).removeClass('arrow-down-hover');
					})
					.mousedown(function() {
						$(this).addClass('arrow-down-active');
						
						clearInterval(this.scrollInterval);
						this.scrollInterval = setInterval(function() {
							content.scrollTop += content.clientHeight * .01;
						}, 1);
						return false;
					})
					.mouseup(function() {
						$(this).removeClass('arrow-down-active');
						clearInterval(this.scrollInterval);
					});
				
				// Set document events
				$(document)
					.mousemove(function(event){
						if (startedDragPos) {
							var position = (event.clientY - startedDragPos) + startedOffsetPos;
							var limit = trackHeight - tabHeight - tabMargins;
							
							if (position < 0) {
								position = 0;
							}
							if (position > limit) {
								position = limit;
							}
							content.scrollTop = (content.scrollHeight - content.clientHeight) * (position / limit);
							return false;
						}
					})
					.mouseup(function() {
						$(".scrollbar-vertical .tab-active").removeClass('tab-active');
						$(".scrollbar-vertical .arrow-up-active").removeClass('arrow-up-active');
						$(".scrollbar-vertical .arrow-down-active").removeClass('arrow-down-active');
						clearInterval(scrollbar.upArrow.scrollInterval);
						clearInterval(scrollbar.downArrow.scrollInterval);
						startedDragPos = null;
					});
				
				// Align the scroll bar every 0 milliseconds
				content.alignInterval = setInterval(alignScrollBars, 1);
				
				// Make sure that the content will be either absolute, relative or fixed
				var contentPosition = $content.css('position');
				if (contentPosition != 'absolute' && contentPosition != 'relative' && contentPosition != 'fixed') 
					contentPosition = 'relative';
				
				// Hide the default scroll bars and insert the new ones
				$content.css({
					overflow: 'hidden',
					position: contentPosition
				}).after(scrollbar)[0];
			}
		});
	};
})(jQuery);